package rexsee.multimedia;

import java.io.File;
import java.io.FileOutputStream;

import rexsee.core.browser.Browser;
import rexsee.core.browser.clazz.JavascriptInterface;
import rexsee.core.utilities.Utilities;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Environment;

public class RexseeImage implements JavascriptInterface {

	public static final String INTERFACE_NAME = "Image";
	@Override
	public String getInterfaceName() {
		return mBrowser.application.resources.prefix + INTERFACE_NAME;
	}
	@Override
	public JavascriptInterface getInheritInterface(Browser childBrowser) {
		return this;
	}
	@Override
	public JavascriptInterface getNewInterface(Browser childBrowser) {
		return new RexseeImage(childBrowser);
	}

	private final Browser mBrowser;
	protected final Context mContext;

	public RexseeImage(Browser browser) {

		mBrowser = browser;
		mContext = browser.getContext();

	}
	public RexseeImage(Context context) {
		mBrowser = null;
		mContext = context;
	}

	public static Bitmap.CompressFormat getFormat(String path) {
		path = path.toLowerCase();
		if (path.endsWith(".jpg") || path.endsWith("jpeg")) return Bitmap.CompressFormat.JPEG;
		else if (path.endsWith(".png")) return Bitmap.CompressFormat.PNG;
		else return null;
	}
	public static boolean saveBitmap(Bitmap bitmap, int quality, String target) {
		if (bitmap == null) return false;
		File tFile = Utilities.prepareWriteFile(target);
		if (tFile == null) return false;
		try {
			FileOutputStream fileOutput = new FileOutputStream(tFile);
			boolean rtn = bitmap.compress(getFormat(target), quality, fileOutput);
			fileOutput.flush();
			fileOutput.close();
			return rtn;
		} catch (Exception e) {
			return false;
		}
	}
	public static Bitmap getGrayScaleBitmap(Bitmap bmpOriginal) {
		int width, height;
		height = bmpOriginal.getHeight();
		width = bmpOriginal.getWidth();
		Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
		Canvas c = new Canvas(bmpGrayscale);
		Paint paint = new Paint();
		ColorMatrix cm = new ColorMatrix();
		cm.setSaturation(0);
		ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
		paint.setColorFilter(f);
		c.drawBitmap(bmpOriginal, 0, 0, paint);
		bmpOriginal.recycle();
		return bmpGrayscale;
	}

	//JavaScript Interface
	public synchronized boolean scale(String source, String target, int width, int height, int quality) {
		try {
			File sFile = Utilities.prepareReadFile(source);
			if (sFile == null) {
				mBrowser.exception(getInterfaceName(), "Error on preparing source file.");
				return false;
			}
			Bitmap sBitmap = scale(BitmapFactory.decodeFile(sFile.getAbsolutePath()), width, height);
			if (sBitmap == null) return false;
			boolean rtn = saveBitmap(sBitmap, quality, target);
			sBitmap.recycle();
			sBitmap = null;
			return rtn;
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
			return false;
		}
	}
	public synchronized boolean scale(String source, String target, int width, int height) {
		return scale(source, target, width, height, 80);
	}
	public synchronized boolean scale(String source, int width, int height) {
		return scale(source, source, width, height, 80);
	}
	public synchronized boolean scaleByRate(String source, String target, float rate) {
		try {
			if (rate <= 0) return false;
			File sFile = Utilities.prepareReadFile(source);
			if (sFile == null) return false;
			Bitmap sBitmap = BitmapFactory.decodeFile(sFile.getAbsolutePath());
			int width = Math.round(sBitmap.getWidth() * rate);
			sBitmap.recycle();
			sBitmap = null;
			return scale(source, target, width, 0, 80);
		} catch (Exception e) {
			return false;
		}
	}
	public synchronized boolean scaleByRate(String source, float rate) {
		return scaleByRate(source, source, rate);
	}
	public synchronized boolean scaleByTargetFileSize(String source, String target, int size) {
		try {
			if (!getFormat(source).toString().equals(getFormat(target).toString())) return false;
			File sFile = Utilities.prepareReadFile(source);
			if (sFile == null) return false;
			float rate = (float) Math.sqrt((float) (size * 1024) / sFile.length());
			return scaleByRate(source, target, rate);
		} catch (Exception e) {
			return false;
		}
	}
	public synchronized boolean scaleByTargetFileSize(String source, int size) {
		return scaleByTargetFileSize(source, source, size);
	}

	public synchronized Bitmap scale(Bitmap sBitmap, int width, int height) {
		int w = sBitmap.getWidth();
		int h = sBitmap.getHeight();
		if (width <= 0 && height <= 0) {
			return null;
		} else if (width <= 0) {
			width = w * height / h;
		} else if (height <= 0) {
			height = h * width / w;
		}
		Bitmap rtn = Bitmap.createScaledBitmap(sBitmap, width, height, false);
		sBitmap.recycle();
		return rtn;
	}
	public synchronized Bitmap rotate(Bitmap sBitmap, int degree) {
		if (sBitmap == null) return null;
		int w = sBitmap.getWidth();
		int h = sBitmap.getHeight();
		Matrix matrix = new Matrix();
		matrix.setRotate(degree);
		Bitmap rtn = Bitmap.createBitmap(sBitmap, 0, 0, w, h, matrix, false);
		sBitmap.recycle();
		return rtn;
	}
	public synchronized Bitmap reverse(Bitmap sBitmap, int mode) {
		if (sBitmap == null) return null;
		Matrix matrix = new Matrix();
		Camera camera = new Camera();
		if (mode == 0) {
			camera.rotateX(180);
		} else if (mode == 1) {
			camera.rotateY(180);
		} else {
			return null;
		}
		camera.getMatrix(matrix);
		int w = sBitmap.getWidth();
		int h = sBitmap.getHeight();
		Bitmap rtn = Bitmap.createBitmap(sBitmap, 0, 0, w, h, matrix, false);
		sBitmap.recycle();
		return rtn;
	}

	public synchronized boolean rotate(String source, String target, int degree, int quality) {
		try {
			File sFile = Utilities.prepareReadFile(source);
			if (sFile == null) {
				mBrowser.exception(getInterfaceName(), "Error on preparing source file.");
				return false;
			}
			Bitmap sBitmap = rotate(BitmapFactory.decodeFile(sFile.getAbsolutePath()), degree);
			if (sBitmap == null) return false;
			boolean rtn = saveBitmap(sBitmap, quality, target);
			sBitmap.recycle();
			sBitmap = null;
			return rtn;
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
			return false;
		}
	}
	public synchronized boolean rotate(String source, int degree, int quality) {
		return rotate(source, source, degree, quality);
	}
	public synchronized boolean cut(String source, String target, int x, int y, int width, int height, int quality) {
		try {
			File sFile = Utilities.prepareReadFile(source);
			if (sFile == null) {
				mBrowser.exception(getInterfaceName(), "Error on preparing source file.");
				return false;
			}
			Bitmap sBitmap = BitmapFactory.decodeFile(sFile.getAbsolutePath());
			sBitmap = Bitmap.createBitmap(sBitmap, x, y, width, height, null, false);
			if (sBitmap == null) return false;
			boolean rtn = saveBitmap(sBitmap, quality, target);
			sBitmap.recycle();
			sBitmap = null;
			return rtn;
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
			return false;
		}
	}
	public synchronized boolean cut(String source, int x, int y, int w, int h, int quality) {
		return cut(source, source, x, y, w, h, quality);
	}
	public synchronized boolean reverse(String source, String target, int mode, int quality) {
		try {
			File sFile = Utilities.prepareReadFile(source);
			if (sFile == null) {
				mBrowser.exception(getInterfaceName(), "Error on preparing source file.");
				return false;
			}
			Bitmap sBitmap = reverse(BitmapFactory.decodeFile(sFile.getAbsolutePath()), mode);
			if (sBitmap == null) return false;
			boolean rtn = saveBitmap(sBitmap, quality, target);
			sBitmap.recycle();
			sBitmap = null;
			return rtn;
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
			return false;
		}
	}
	public synchronized boolean reverse(String source, int mode, int quality) {
		return reverse(source, source, mode, quality);
	}

	public String getSize(String path) {
		Rect rect = getRect(path);
		String rtn = "{";
		rtn += "\"width\":" + rect.width();
		rtn += ",\"height\":" + rect.height();
		rtn += "}";
		return rtn;
	}

	public Rect getRect(String path) {
		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(Uri.parse(path).getPath(), options);
		Rect rtn = new Rect();
		rtn.left = 0;
		rtn.top = 0;
		rtn.right = options.outWidth;
		rtn.bottom = options.outHeight;
		return rtn;
	}

	public String getExif(String path, String tag) {
		String p = path.trim().toLowerCase();
		if (!p.startsWith("file://")) {
			mBrowser.exception(getInterfaceName(), "Only the images in the external storage can be set exif.");
			return "";
		}
		if (p.startsWith("file:///android_asset")) {
			if (!(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))) return "";
			String sdPath = "file://" + Environment.getExternalStorageDirectory().getAbsolutePath() + "/tmpAssetImage.jpg";
			if (!Utilities.copyAssetToExternalStorage(mBrowser.getContext(), path.substring(22), sdPath)) return "";
			path = sdPath;
		}
		try {
			ExifInterface exif = new ExifInterface(Uri.parse(path).getPath());
			String rtn = exif.getAttribute(tag);
			return (rtn == null) ? "" : rtn;
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
			return "";
		}
	}
	public boolean setExif(String path, String tag, String value) {
		String p = path.trim().toLowerCase();
		if (!p.startsWith("file://") || p.startsWith("file:///android_asset")) {
			mBrowser.exception(getInterfaceName(), "Only the images in the external storage can be set exif.");
			return false;
		}
		try {
			ExifInterface exif = new ExifInterface(Uri.parse(path).getPath());
			exif.setAttribute(tag, value);
			exif.saveAttributes();
			return true;
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
			return false;
		}
	}

}
